#pragma once
#include <functional>
#include <vector>
#include <memory>
#include "Helper.h"
#include "DXContext.h"
#include "PerformanceTimer.h"

namespace DXBase
{
	namespace Samples
	{
		// a class than can render DirectX code from other C++ sample quite easily
		// make a new ISceneData instance and add it to a Scene
		[Windows::Foundation::Metadata::WebHostHidden]
		public interface class ISceneData
		{
			Windows::Foundation::IAsyncOperation<bool>^ LoadAsync(DXContext^ ctxt);
			void Reset();
			void Resize(DXContext^ ctxt);
			void Render(DXContext^ ctxt, PerformanceTimer^ timer);
		};

		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class SceneRenderArgs sealed
		{
		public:
			SceneRenderArgs()
			{
				UpdateTimer = true;
				PaintBackground = true;
			}
			property bool UpdateTimer;
			property bool PaintBackground;
		};

		// a class to render bits of DirectX from other sample
		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class Scene sealed
		{
		public:
			Scene();
			Scene(DXContext^ ctxt);

			property PerformanceTimer^ Timer { PerformanceTimer^ get() { return mTimer; } }

			property Windows::Foundation::Collections::IVectorView<ISceneData^>^ Parts { Windows::Foundation::Collections::IVectorView<ISceneData^>^ get() { return mParts->GetView(); } }
			void Add(ISceneData^ asset);
			void RemoveAt(int index);

			void RenderFrame() { RenderFrame(ref new SceneRenderArgs()); }
			void RenderFrame(SceneRenderArgs^ args);

			property Windows::UI::Color Background;
			property DXBase::DXContext^ Context { DXBase::DXContext^ get() { return mContext; } }

			Windows::Foundation::IAsyncAction^ LoadAsync();
			property bool IsLoaded { bool get(); }

		private:
			~Scene();
			void Init(DXContext^ ctxt);
			DXContext^ mContext;
			void OnContextPropertyChanged(Platform::Object^ source, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ args);
			Windows::Foundation::EventRegistrationToken pctoken;


			DebugObject debug;

			PerformanceTimer^ mTimer;

			struct ScenePartData
			{
				bool sized, loading, loaded;
			};
			Platform::Collections::Vector<ISceneData^>^ mParts;
			std::vector<std::shared_ptr<ScenePartData>> partsData;

			// wait for load
			volatile SHORT loadingcount;
			HANDLE loadingwait;

			// manage individual scene
			void GetAt(int index, ISceneData^& sc, std::shared_ptr<ScenePartData>& pd);
			void OnLoad(ISceneData^ sc, std::shared_ptr<ScenePartData> pd);
			void OnReset(ISceneData^ sc, std::shared_ptr<ScenePartData> pd);
			void OnResize(ISceneData^ sc, std::shared_ptr<ScenePartData> pd);
			void OnRender(ISceneData^ sc, std::shared_ptr<ScenePartData> pd);
		};
	}
}